package edu.towson.cosc.cosc455.ddange1.markdowncompiler;
import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

public class mySyntaxAnalyzer implements SyntaxAnalyzer {
	private myLexicalAnalyzer lexer = new myLexicalAnalyzer();
	
	//adds the token to the stack and clears the token information
	public void addToken()
	{
		compiler.info.push(compiler.token); 
		lexer.clearLexer();
	}
	
    public void document() throws CompilerException {
    		lexer.getNextToken();
    		//#START DOCUMENT should not be hard coded. Call it from somewhere else
            if(!compiler.token.equalsIgnoreCase("#START DOCUMENT")){
            	compiler.createDocument = false; 
            	String message = "A #START DOCUMENT annotation was expected when a " +
                                    compiler.token + " was found!";
                throw new CompilerException(message);
            }
            else{
            	addToken();
            }
            
            lexer.getNextToken();
            
            if(compiler.token.equalsIgnoreCase("#START DEFINE")){
            	while(compiler.token.equalsIgnoreCase("#START DEFINE")){
            		define();
            		lexer.getNextToken();
            	}
        	}
        	if(compiler.token.equalsIgnoreCase("#START HEAD")){
        		head();
        		lexer.getNextToken();
        	}
        	
            body();
            if(!compiler.token.equalsIgnoreCase("#END DOCUMENT")){
                compiler.createDocument = false; 
                String message = "A #END DOCUMENT annotation was expected when a " +
                                    compiler.token + " was found!";
                throw new CompilerException(message);
            }
            else{
            	addToken();
            }
            if(compiler.fileText.length() != 0){
            	compiler.createDocument = false; 
            	String message = "There is unexpected information found. " + 
            			"Please delete " + compiler.fileText;
            	throw new CompilerException(message);
            }
    }
   
    public void body() throws CompilerException {
    	boolean endBody = false;
    	while(!endBody){
    		if(compiler.token.equalsIgnoreCase("#START PARAGRAPH")){
    			paragraph();
    		}
    		else if(compiler.token.equalsIgnoreCase("#START BOLD")){
    			bold();
    		}
    		else if(compiler.token.equalsIgnoreCase("#START ITALICS")){
    			italics();    				
    		}
    		else if(compiler.token.equalsIgnoreCase("#START LIST")){
    			list();    	
    		}
    		else if(compiler.token.equalsIgnoreCase("#START USE")){
    			use();
    		}
    		else if(compiler.token.equalsIgnoreCase("#NEWLINE")){
    			addToken();
    		}
    		else if(lexer.isText(compiler.token)){
    			addToken();
    		}
    		else{
    			endBody = true;
    		}
    		if(!endBody){
    			lexer.getNextToken();
    		}
    	}       	
}

	public void head() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START HEAD")){
        	compiler.createDocument = false; 
        	String message = "A #START HEAD annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
        
        lexer.getNextToken();
        title();
        
        lexer.getNextToken();
        if(!compiler.token.equalsIgnoreCase("#END HEAD")){
            compiler.createDocument = false; 
            String message = "A #END HEAD annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void title() throws CompilerException {
        if(!compiler.token.equalsIgnoreCase("#START TITLE")){
        	compiler.createDocument = false; 
        	String message = "A #START TITLE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
        
        lexer.getNextToken();
        if(lexer.isText(compiler.token)){
        	//should be text or at least a space
        	addToken();
        }
        
        lexer.getNextToken();
        if(!compiler.token.equalsIgnoreCase("#END TITLE")){
            compiler.createDocument = false; 
            String message = "A #END TITLE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void paragraph() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START PARAGRAPH")){
        	compiler.createDocument = false; 
        	String message = "A #START PARAGRAPH annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexer.getNextToken();
		while(!compiler.token.equalsIgnoreCase("#END PARAGRAPH")){
			//---------------Paragraph---------------------
			if(compiler.token.equalsIgnoreCase("#START PARAGRAPH")){
				paragraph();
			}
			//---------------definition--------------------
			else if(compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			//---------------use---------------------------
			else if(compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			//---------------bold--------------------------
			else if(compiler.token.equalsIgnoreCase("#START BOLD")){
				bold();
			}
			//---------------Italics-----------------------
			else if(compiler.token.equalsIgnoreCase("#START ITALICS")){
				italics();
			}
			//---------------list--------------------------
			else if(compiler.token.equalsIgnoreCase("#START LIST")){
				list();
			}
			//---------------newline-----------------------
			else if(compiler.token.equalsIgnoreCase("#NEWLINE")){
				//add the newLine tag to the stack
				addToken();
			}
			else if(lexer.isText(compiler.token))
			{
				addToken();
			}
			else{
				//Case that the token is a tag that 
					//cannot be in the paragraph function
				compiler.createDocument = false; 
				String message = "Tag is not applicable to this "
						+ "tag. ";
				throw new CompilerException(message);
			}
			lexer.getNextToken();
		}
        
        if(!compiler.token.equalsIgnoreCase("#END PARAGRAPH")){
            compiler.createDocument = false; 
            String message = "A #END PARAGRAPH annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
    	}
	}

	public void bold() throws CompilerException {
		if(lexer.isEmptySpace(compiler.token)){
			addToken();
			lexer.getNextToken();
		}
		if(!compiler.token.equalsIgnoreCase("#START BOLD")){
        	compiler.createDocument = false; 
        	String message = "A #START BOLD annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexer.getNextToken();
		
		while(!compiler.token.equalsIgnoreCase("#END BOLD")){
			//---------------definition--------------------
			if(compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			//---------------use---------------------------
			else if(compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			//---------------italics-----------------------
			else if(compiler.token.equalsIgnoreCase("#START ITALICS")){
				italics();
			}
			//---------------newline-----------------------
			else if(compiler.token.equalsIgnoreCase("#NEWLINE")){
				//add the newLine tag to the stack
				addToken();
			}
			else if(lexer.isText(compiler.token))
			{
				addToken();
			}
			else{
				//Case that the token is a tag that 
					//cannot be in the paragraph function
				compiler.createDocument = false; 
				String message = "Tag is not applicable to this "
						+ "tag. ";
				throw new CompilerException(message);
			}
			
			lexer.getNextToken();
		}
        
        if(!compiler.token.equalsIgnoreCase("#END BOLD")){
            compiler.createDocument = false; 
            String message = "A #END BOLD annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void italics() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START ITALICS")){
        	compiler.createDocument = false; 
        	String message = "A #START ITALICS annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexer.getNextToken();
		
		while(!compiler.token.equalsIgnoreCase("#END ITALICS")){
			//---------------definition--------------------
			if(compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			//---------------use---------------------------
			else if(compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			//---------------newline-----------------------
			else if(compiler.token.equalsIgnoreCase("#NEWLINE")){
				//add the newLine tag to the stack
				addToken();
			}
			else if(lexer.isText(compiler.token))
			{
				addToken();
			}
			else{
				//Case that the token is a tag that 
					//cannot be in the paragraph function
				compiler.createDocument = false; 
				String message = "Tag is not applicable to this "
						+ "tag. ";
				throw new CompilerException(message);
			}
			lexer.getNextToken();
		}
        
        if(!compiler.token.equalsIgnoreCase("#END ITALICS")){
            compiler.createDocument = false; 
            String message = "A #END ITALICS annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void list() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START LIST")){
	       	compiler.createDocument = false; 
	       	String message = "A #START LIST annotation was expected when a " +
	                      compiler.token + " was found!";
	        throw new CompilerException(message);
	    }
		else{
			addToken();
		}
	        
	    lexer.getNextToken();
	    while((!compiler.token.equals("#END LIST")) && (!compiler.fileText.isEmpty())){
	       	item();
	       	lexer.getNextToken();
	    }

	    if(!compiler.token.equalsIgnoreCase("#END LIST")){
	        compiler.createDocument = false; 
	        String message = "A #END LIST annotation was expected when a " +
	                  compiler.token + " was found!";
	        throw new CompilerException(message);
	    }
	    else{
	       	addToken();
	    }
	}

	public void item() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START ITEM")){
        	compiler.createDocument = false; 
        	String message = "A #START ITEM annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
		
		lexer.getNextToken();
		while(!compiler.token.equalsIgnoreCase("#END ITEM")){
			//---------------definition--------------------
			if(compiler.token.equalsIgnoreCase("#START LIST")){
				list();
			}
			else if(compiler.token.equalsIgnoreCase("#START DEFINE")){
				define();
			}
			//---------------use---------------------------
			else if(compiler.token.equalsIgnoreCase("#START USE")){
				use();
			}
			//---------------newline-----------------------
			else if(compiler.token.equalsIgnoreCase("#NEWLINE")){
				//add the newLine tag to the stack
				addToken();
			}
			else if(lexer.isText(compiler.token)){
				addToken();
			}
			else{
				//Case that the token is a tag that 
					//cannot be in the paragraph function
				compiler.createDocument = false; 
				String message = "Tag is not applicable to this "
						+ "tag. ";
				throw new CompilerException(message);
			}
			lexer.getNextToken();
		}
		
        if(!compiler.token.equalsIgnoreCase("#END ITEM")){
            compiler.createDocument = false; 
            String message = "A #END ITEM annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void audio() throws CompilerException {
		 if(!compiler.token.equalsIgnoreCase("#START AUDIO")){
	        	compiler.createDocument = false; 
	        	String message = "A #START AUDIO annotation was expected when a " +
	                                compiler.token + " was found!";
	            throw new CompilerException(message);
	        }
		 else{
			 addToken();
		 }
	        
		 lexer.getNextToken();
		 if(lexer.isText(compiler.token))
			{
				addToken();
				lexer.getNextToken();
			}
		 if(lexer.isEmptySpace(compiler.token)){
				addToken();
				lexer.getNextToken();
			}
	     if(!compiler.token.equalsIgnoreCase("#END AUDIO")){
	            compiler.createDocument = false; 
	            String message = "A #END AUDIO annotation was expected when a " +
	                                compiler.token + " was found!";
	            throw new CompilerException(message);
	        }
	     else{
	    	 addToken();
	     }
	}

	public void video() throws CompilerException {
		 if(!compiler.token.equalsIgnoreCase("#START VIDEO")){
	        	compiler.createDocument = false; 
	        	String message = "A #START VIDEO annotation was expected when a " +
	                                compiler.token + " was found!";
	            throw new CompilerException(message);
	        }
		 else{
			 addToken();
		 }
	        
		 lexer.getNextToken();
		 if(lexer.isText(compiler.token))
			{
				addToken();
				lexer.getNextToken();
			}
		 
	     if(!compiler.token.equalsIgnoreCase("#END VIDEO")){
	            compiler.createDocument = false; 
	            String message = "A #END VIDEO annotation was expected when a " +
	                                compiler.token + " was found!";
	            throw new CompilerException(message);
	     }
	     else{
	    	 addToken();
	     }
	}

	public void define() throws CompilerException {
		if(!compiler.token.equalsIgnoreCase("#START DEFINE")){
        	compiler.createDocument = false; 
        	String message = "A #START DEFINE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
		else{
			addToken();
		}
        lexer.getNextToken();
        if(!compiler.token.equalsIgnoreCase("#NAME")){
        	addToken();
        	compiler.createDocument = false; 
        	String message = "A #NAME annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
        
        lexer.getNextToken(); 
        //should be the name of the object in plain text format
        if(lexer.isText(compiler.token)){
        	addToken();
        }
        else{
        	compiler.createDocument = false; 
        	String message = "The name of the object should be text only.";
        	throw new CompilerException(message);
        }
        		
        lexer.getNextToken();
        if(!compiler.token.equalsIgnoreCase("#VALUE")){
        	compiler.createDocument = false; 
        	String message = "A #VALUE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
        
        lexer.getNextToken();
        //should be the value of the object in plain text format
        if(lexer.isText(compiler.token)){
        	addToken();
        	lexer.getNextToken();
        }
        else{
        	compiler.createDocument = false; 
        	String message = "The value of the object should be text only.";
        	throw new CompilerException(message);
        }
        
        if(compiler.token.equalsIgnoreCase("#START DEFINE")){
        	define();
        	lexer.getNextToken();
        }

        if(!compiler.token.equalsIgnoreCase("#END DEFINE")){
            compiler.createDocument = false; 
            String message = "A #END DEFINE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}

	public void use() throws CompilerException {
        if(!compiler.token.equalsIgnoreCase("#START USE")){
        	compiler.createDocument = false; 
        	String message = "A #START USE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
        
        lexer.getNextToken();
        if(lexer.isText(compiler.token)){
        //should be text unless there is no space between the 
        	//START USE and END USE tags
        addToken();
        lexer.getNextToken();
        }
        
        if(!compiler.token.equalsIgnoreCase("#END USE")){
            compiler.createDocument = false; 
            String message = "A #END USE annotation was expected when a " +
                                compiler.token + " was found!";
            throw new CompilerException(message);
        }
        else{
        	addToken();
        }
	}
}
